﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace UdpPeer
{
    /// <summary>
    /// Tcp节点 
    /// </summary>
    public class TcpPeerNode
    {
        /// <summary>
        /// Tcp节占客户端对像
        /// </summary>
        private System.Net.Sockets.Socket client;

        /// <summary>
        /// 客户端对像
        /// </summary>
        public System.Net.Sockets.Socket Client
        {
            get { return client; }
        }

        /// <summary>
        /// 服务节点
        /// </summary>
        protected Socket ServerListen;

        /// <summary>
        /// 联接到远程点
        /// </summary>
        /// <param name="ep"></param>
        /// <returns></returns>
        public bool Connection(System.Net.IPEndPoint ep)
        {
            client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            SetSocketReuse(client);
            client.Connect(ep);
            

            return true;
        }

        /// <summary>
        /// 是否正在运行
        /// </summary>
        public bool IsRuning { get; set; }

        /// <summary>
        /// 开始
        /// </summary>
        public void Start()
        {
            Stop();
            //创建服务
            CreateServer();
            IsRuning = true;
        }
        /// <summary>
        /// 结束
        /// </summary>
        public void Stop()
        {
            IsRuning = false;
            try
            {
                ServerListen.Close();
                ServerListen.Dispose();
                ClientConnections.ToArray().ToList().ForEach((c) =>
                {
                    ConnClose(c.Value);
                });
            }
            catch (SocketException) { }
            catch (ObjectDisposedException) { }
            catch (NullReferenceException) { }
        }

        /// <summary>
        /// 创建Server
        /// </summary>
        public void CreateServer()
        {
            //创建新的SocketServer
            if (client != null && client.Connected)
            {
                ServerListen = new Socket(client.AddressFamily, client.SocketType, client.ProtocolType);
                SetSocketReuse(ServerListen);
                //用本地终节点邦定做服务端
                ServerListen.Bind(client.LocalEndPoint);
                //开始监听数据
               ServerListen.Listen(10);

                //添加开始 accept
                PeerServerNodeThreadStudio.Instance.PlushAccept(StartAccept);
            }
        }

        /// <summary>
        /// 设置端口,地址重用
        /// </summary>
        /// <param name="socket">socket</param>
        public static void SetSocketReuse(Socket socket)
        {
            //可以帮定同一端口
            socket.ExclusiveAddressUse = true;
            //表示IP端口重用
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

        }

        #region 客户端联接池
        /// <summary>
        /// 接收SAEA池集合
        /// </summary>
        private ConcurrentStack<SocketAsyncEventArgs> ReceiveSocketArgsPool = new ConcurrentStack<SocketAsyncEventArgs>();

        /// <summary>
        /// 初始化接收socketargs对象池
        /// </summary>
        protected void InitReceiveSocketArgsPool()
        {
            for (int ndx = 0; ndx < 3000; ndx++)
            {
                ReceiveSocketArgsPool.Push(CreateReceiveSocketArgs());
            }
        }

        /// <summary>
        /// 创建一个接收SAEA对象,设置最大接收字节数
        /// </summary>
        /// <returns></returns>
        protected virtual SocketAsyncEventArgs CreateReceiveSocketArgs()
        {
            SocketAsyncEventArgs e = new SocketAsyncEventArgs();
            e.Completed += IO_Comleted;
            return e;
        }




        /// <summary>
        /// 租赁一个接收SAEA对象
        /// </summary>
        /// <returns></returns>
        protected virtual SocketAsyncEventArgs RentReveiveSocketArgs()
        {
            SocketAsyncEventArgs e;

            return ReceiveSocketArgsPool.TryPop(out e) ? e : CreateReceiveSocketArgs();
        }

        /// <summary>
        /// 归还一个接收SAEA参数
        /// </summary>
        /// <param name="e">还池</param>
        protected virtual void GivebackReceiveSocketArgs(SocketAsyncEventArgs e)
        {
            if (e != null)
            {
                e.UserToken = null;
                ReceiveSocketArgsPool.Push(e);
            }
        }

        #endregion


        #region 接收数据

        /// <summary>
        /// 客户端联接
        /// </summary>
        private System.Collections.Concurrent.ConcurrentDictionary<string, SocketAsyncEventArgs> cientConnections = new ConcurrentDictionary<string, SocketAsyncEventArgs>();
        /// <summary>
        /// 客户端联接
        /// </summary>
        public System.Collections.Concurrent.ConcurrentDictionary<string, SocketAsyncEventArgs> ClientConnections
        {
            get { return cientConnections; }
        }

        /// <summary>
        /// 接收数据Handler,数据来源节点,用于处理的异步对像
        /// </summary>
        public Action<byte[], string, SocketAsyncEventArgs> ReceiveHandler;

        /// <summary>
        /// 开始接入联接
        /// </summary>
        protected void StartAccept()
        {

            var args = RentReveiveSocketArgs();
            //删除数据
            args.Completed -= IO_Comleted;
            args.Completed += IO_AcceptCompleted;

            try
            {
                if (!ServerListen.AcceptAsync(args))
                {
                    IO_AcceptCompleted(this, args);
                }
            }
            catch
            {
                try
                {
                    ServerListen.Close();
                    ServerListen.Dispose();
                }
                catch
                {
                }
            }
        }
        /// <summary>
        /// 联接接收
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void IO_AcceptCompleted(object sender, SocketAsyncEventArgs e)
        {
            //删除数据
            e.Completed -= IO_AcceptCompleted;
            e.Completed += IO_Comleted;
            //接收的套节字
            if (e.AcceptSocket != null)
            {
                string key = e.RemoteEndPoint.ToString();
                e.UserToken = key;
                //添加成功则进行key处理
                if (ClientConnections.TryAdd(key, e))
                {
                    var buffer = new byte[65535 * 2];
                    //设置缓冲区
                    e.SetBuffer(buffer, 0, buffer.Length);
                    //开始接收数据
                    StartReceive(e);
                }
                else
                {
                    e.AcceptSocket.Close();
                }
            }

        }
        /// <summary>
        /// 开始接收数据
        /// </summary>
        /// <param name="e"></param>
        public void StartReceive(SocketAsyncEventArgs e)
        {
            try
            {
                if (!e.AcceptSocket.ReceiveAsync(e))
                {
                    IO_Comleted(this, e);
                }
            }
            catch
            {

                ConnClose(e);
            }
        }
        /// <summary>
        /// 接收后的完成功能
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void IO_Comleted(object sender, SocketAsyncEventArgs e)
        {
            try
            {
                if (e.UserToken != null)
                {
                    //发送数据OK
                    if (e.SocketError == SocketError.Success)
                    {
                        if (e.BytesTransferred > 0)
                        {
                            //转入外部委托处理
                            if (ReceiveHandler != null)
                            {
                                byte[] array = new byte[e.BytesTransferred];
                                Buffer.BlockCopy(e.Buffer, 0, array, 0, array.Length);
                                ReceiveHandler(array, e.UserToken.ToString(), e);
                            }
                        }
                        else
                        {
                            ConnClose(e);
                        }
                    }
                    else
                    {
                        e.AcceptSocket.Close();
                    }
                }
            }
            finally
            {
                //拉收数据
                StartReceive(e);
            }
        }
        public void ConnClose(SocketAsyncEventArgs e)
        {
            try
            {
                if (e.UserToken != null)
                {
                    //移除对像
                    SocketAsyncEventArgs xt;
                    ClientConnections.TryRemove(e.UserToken.ToString(), out xt);
                }
                //关闭socket
                e.AcceptSocket.Close();
            }
            finally
            {
                //还池
                GivebackReceiveSocketArgs(e);
            }
        }

        #endregion

        /// <summary>
        /// 服务节点线程处理,工具
        /// </summary>
        internal class PeerServerNodeThreadStudio
        {

            private PeerServerNodeThreadStudio() { Init(); }

            private static readonly PeerServerNodeThreadStudio instance = new PeerServerNodeThreadStudio();
            /// <summary>
            /// 访问单例
            /// </summary>
            public static PeerServerNodeThreadStudio Instance
            {
                get { return PeerServerNodeThreadStudio.instance; }
            }




            /// <summary>
            /// 添加一个接入
            /// </summary>
            public void PlushAccept(Action act)
            {
                actqueue.Enqueue(act);
            }

            Queue<Action> actqueue = new Queue<Action>();

            /// <summary>
            /// 开始初始化
            /// </summary>
            protected void Init()
            {


                System.Threading.Tasks.Task.Factory.StartNew(() =>
                {
                    while (true)
                    {
                        Action act = null;
                        if (actqueue.Count > 0)
                        {
                            act = actqueue.Dequeue();
                        }
                        if (act != null)
                        {
                            //所有的都加入到一个线程中进行处理.
                            act();
                        }
                        else
                        {
                            System.Threading.Thread.Sleep(10);
                        }
                    }
                });
            }


        }



    }
}
